package us.feng.tinyspring.aop.aspectj;

import java.lang.reflect.Method;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.ShadowMatch;

import us.feng.tinyspring.aop.ClassFilter;
import us.feng.tinyspring.aop.MethodMatcher;
import us.feng.tinyspring.aop.support.ExpressionPointcut;

public class AspectJExpressionPointcut implements ExpressionPointcut,MethodMatcher,ClassFilter{

	private String expression;
	
	private PointcutExpression pointcutExpression;
	
	private PointcutParser pointcutParser;
	
	public AspectJExpressionPointcut(){
		this.pointcutParser=PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
	}
	
	private void checkReadyToMatch() {
		if (getExpression() == null) {
			throw new IllegalStateException("Must set property 'expression' before attempting to match");
		}
		if (this.pointcutExpression == null) {
			try{
				this.pointcutExpression = buildPointcutExpression();
			}catch (Exception e) {
				// TODO: handle exception
			}
		}
	}
	
	private PointcutExpression buildPointcutExpression() throws IllegalArgumentException {
		return pointcutParser.parsePointcutExpression(getExpression());
	}
	
	@Override
	public ClassFilter getClassFilter() {
		return this;
	}

	@Override
	public MethodMatcher getMethodMatcher() {
		return this;
	}

	@Override
	public String getExpression() {
		return this.expression;
	}
	
	public void setExpression(String expression){
		this.expression=expression;
	}

	@Override
	public boolean matches(Class<?> clazz) {
		checkReadyToMatch();
		return pointcutExpression.couldMatchJoinPointsInType(clazz);
	}

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		checkReadyToMatch();
		ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
		if(shadowMatch.alwaysMatches()){
			return true;
		}else if(shadowMatch.neverMatches()){
			return false;
		}
		return false;
	}
	

}
